home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
mint104s.zoo
/
mint.src
/
tty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-08
|
19KB
|
803 lines
/*
Copyright 1990,1991,1992 Eric R. Smith.
Copyright 1992 Atari Corporation.
All rights reserved.
*/
/*
* read/write routines for TTY devices
*/
#include "mint.h"
static void _erase P_((FILEPTR *, int));
static int escseq P_((struct tty *, int));
/* setting a special character to this value disables it */
#define UNDEF 0
/* default terminal characteristics */
struct tty default_tty = {
0, /* process group */
0, /* state */
0, /* use_cnt */
0, /* reserved short */
{
13, 13, /* input speed == output speed == 9600 baud */
CTRL('H'), /* erase */
CTRL('U'), /* kill */
T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */
},
{
CTRL('C'), /* interrupt */
CTRL('\\'), /* quit */
CTRL('Q'), /* start */
CTRL('S'), /* stop */
CTRL('D'), /* EOF */
'\r' /* alternate end of line */
},
{
CTRL('Z'), /* suspend */
CTRL('Y'), /* suspend after read */
CTRL('R'), /* reprint */
UNDEF, /* flush output */
CTRL('W'), /* erase word */
CTRL('V') /* quote next char */
},
{
0, 0, 0, 0 /* window size is unknown */
},
0, /* no process is selecting us for reading */
0, /* or for writing */
0 /* use default XKEY map */
};
#define _put(f, c) (tty_putchar((f), (c), RAW))
static void
_erase(f, c)
FILEPTR *f;
int c;
{
_put(f, '\010');
_put(f, ' ');
_put(f, '\010');
/* watch out for control characters -- they're printed as e.g. "^C" */
/* BUG: \t is messed up. We really need to keep track of the output
* column
*/
if (c >= 0 && c < ' ' && c != '\t') {
_put(f, '\010'); _put(f, ' '); _put(f, '\010');
}
}
#define put(f, c) { if (mode & T_ECHO) _put(f, c); }
#define erase(f, c) { if (mode & T_ECHO) _erase(f, c); }
long
tty_read(f, buf, nbytes)
FILEPTR *f;
void *buf;
long nbytes;
{
long r;
long bytes_read = 0;
unsigned char ch, *ptr;
int rdmode, mode;
struct tty *tty;
tty = (struct tty *)f->devinfo;
assert(tty != 0);
if (f->flags & O_HEAD) { /* pty server side? */
rdmode = RAW; /* yes -- always raw mode */
mode = T_RAW;
}
else if (curproc->domain == DOM_MINT) { /* MiNT domain process? */
mode = tty->sg.sg_flags;
rdmode = COOKED|NOECHO;
if ( mode & (T_RAW | T_CBREAK) ) {
rdmode = (mode & T_RAW) ? RAW : COOKED;
}
if (mode & T_XKEY)
rdmode |= ESCSEQ;
}
else {
rdmode = COOKED|NOECHO;
mode = T_TOS | T_ECHO;
}
ptr = buf;
while (bytes_read < nbytes) {
r = tty_getchar(f, rdmode);
if (r < 0) {
tty_error:
DEBUG(("tty_read: tty_getchar returned %ld", r));
return (bytes_read) ? bytes_read : r;
}
else if (r == MiNTEOF)
return bytes_read;
ch = r & 0xff;
if ( (mode & T_CRMOD) && (ch == '\r') )
ch = '\n';
/* 1 character reads in TOS mode are always raw */
if (nbytes == 1 && (mode & T_TOS)) {
put(f, ch);
*ptr = ch;
return 1;
}
/* T_CBREAK mode doesn't do erase or kill processing */
/* also note that setting a special character to UNDEF disables it */
if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
if ((char)ch == tty->sg.sg_erase) { /* backspace */
if (bytes_read > 0) {
--ptr;
erase(f, *ptr);
bytes_read--;
}
continue;
}
else if ((mode & T_TOS) && ch == CTRL('X')) {
while (bytes_read > 0) {
--ptr;
erase(f, *ptr);
bytes_read--;
}
continue;
}
else if ((char)ch ==tty->ltc.t_rprntc ||
(char)ch == tty->sg.sg_kill) {
if (mode & T_TOS)
put(f, '#');
put(f, '\r');
put(f, '\n');
ptr = buf;
if ((char)ch == tty->sg.sg_kill) {
bytes_read = 0;
}
else {
for (r = 0; r < bytes_read; r++, ptr++)
put(f, *ptr);
}
continue;
}
else if ((char)ch == tty->ltc.t_werasc) {
while (bytes_read > 0 &&
!(ptr[-1] == ' ' || ptr[-1] == '\t')) {
ptr--;
erase(f, *ptr);
bytes_read--;
}
continue;
}
else if ((char)ch == tty->ltc.t_lnextc) {
put(f, '^');
put(f, '\b');
r = tty_getchar(f, RAW);
if (r < 0)
goto tty_error;
else if (r == MiNTEOF)
return bytes_read;
ch = r & 0xff;
goto stuff_it;
}
else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
return bytes_read;
}
/* both T_CBREAK and T_COOKED modes have to do signals, though */
if ((rdmode & COOKED) && ch != UNDEF) {
if ((char)ch == tty->tc.t_intrc
|| (char)ch == tty->tc.t_quitc
|| (char)ch == tty->ltc.t_dsuspc
|| (char)ch == tty->ltc.t_suspc
) {
/* the device driver raised the appropriate signal; if we get here, the
signal was caught by the user (or ignored). flush buffers and continue
*/
if (!(tty->sg.sg_flags & T_NOFLSH)) {
DEBUG(("tty_read: flushing input"));
bytes_read = 0;
ptr = buf;
}
continue;
}
else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
put(f, '\r');
if (!(mode & T_TOS)) {
*ptr = ch;
put(f, '\n');
bytes_read++;
}
return bytes_read;
}
}
/* do the following for both RAW and COOKED mode */
stuff_it:
*ptr++ = ch;
if (ch < ' ' && ch != '\t') { /* ch is unsigned */
put(f, '^'); put(f, ch+'@');
}
else
put(f, ch);
bytes_read++;
/* for RAW mode, if there are no more characters then break */
if ( (mode & (T_RAW|T_CBREAK)) &&
!((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
r = 1;
(void)(*f->dev->ioctl)(f, FIONREAD, &r);
if (r <= 0) break;
}
}
return bytes_read;
}
long
tty_write(f, buf, nbytes)
FILEPTR *f;
const void *buf;
long nbytes;
{
unsigned const char *ptr;
long c;
long bytes_written;
int mode, rwmode;
struct tty *tty;
int use_putchar = 0;
static long cr_char = '\r';
#define LBUFSIZ 128
long lbuf[LBUFSIZ];
tty = (struct tty *)f->devinfo;
assert(tty != 0);
ptr = buf;
if (f->flags & O_HEAD) {
use_putchar = 1;
mode = T_RAW;
}
else if (curproc->domain == DOM_TOS)
/* for TOS programs, 1 byte writes are always in raw mode */
mode = (nbytes == 1) ? T_RAW : T_TOS;
else
mode = tty->sg.sg_flags;
rwmode = (mode & T_RAW) ? RAW : COOKED;
bytes_written = 0;
/*
* "mode" can now be reduced to just T_CRMODE or not
*/
if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
!(mode & T_RAW))
mode = T_CRMOD;
else
mode = 0;
/*
* we always write at least 1 byte with tty_putchar, since that takes
* care of job control and terminal states. After that, we may be able
* to use (*f->dev->write) directly.
*/
if (nbytes == 0) return bytes_written;
c = *ptr++;
if (c == '\n' && mode) { /* remember, "mode" now means CRMOD */
tty_putchar(f, cr_char, rwmode);
}
tty_putchar(f, c, rwmode);
nbytes--;
bytes_written++;
if (use_putchar) {
while (nbytes-- > 0) {
c = *ptr++;
if (c == '\n' && mode)
tty_putchar(f, cr_char, rwmode);
tty_putchar(f, c, rwmode);
bytes_written++;
}
} else {
/* write in big chunks if possible; but never more than 1 line
* (so that ^S/^Q can happen reasonably quickly for the user)
*/
long bytes_to_write = 0;
long *s = lbuf;
while (nbytes-- > 0) {
c = *ptr++;
if (c == '\n') {
if (bytes_to_write) {
(*f->dev->write)(f, (char *)lbuf,
bytes_to_write);
bytes_to_write = 0;
s = lbuf;
}
if (mode) /* i.e. T_CRMODE */
tty_putchar(f, cr_char, rwmode);
tty_putchar(f, (long)c, rwmode);
bytes_written++;
} else {
*s++ = c;
bytes_written++;
bytes_to_write += 4;
if (bytes_to_write >= LBUFSIZ*4) {
(*f->dev->write)(f, (char *)lbuf,
bytes_to_write);
bytes_to_write = 0;
s = lbuf;
}
}
}
if (bytes_to_write) {
(*f->dev->write)(f, (char *)lbuf, bytes_to_write);
}
}
return bytes_written;
}
/* some notable scan codes */
#define K_INSERT 0x52
#define K_HOME 0x47
#define K_UNDO 0x61
#define K_HELP 0x62
#define CURS_UP 0x48
#define CURS_DN 0x50
#define CURS_RT 0x4d
#define CURS_LF 0x4b
#define F_1 0x3b